package com.secret.view;

import com.secret.utils.AesService;
import com.secret.utils.SHA256;
import com.sun.javafx.webkit.WebConsoleListener;
import javafx.concurrent.Worker;
import javafx.geometry.Insets;
import javafx.scene.control.Alert;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.Consumer;

public class Editor extends VBox {
    static {
        WebConsoleListener.setDefaultListener(new WebConsoleListener() {
            BufferedWriter writer = null;

            {
                try {
                    writer = new BufferedWriter(new FileWriter("log.txt"));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            };

            @Override
            public void messageAdded(WebView webView, String message, int lineNumber, String sourceId) {
                String log = "行号: %s ， 消息: %s , sourceId: %s".formatted(lineNumber , message , sourceId);
                System.out.println(log);
                try {
                    writer.write(log);
                    writer.write("\n");
                    writer.flush();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }

    /**
     * 密码错误
     */
    private boolean passwordError = false;


    private Label title;

    private File file;
    private AesService aesService;

    private WebEngine engine;
    private JavaBridge javaBridge;

    private Consumer<Void> hideListener;

    public Editor(File file , String password , Consumer<Void> hideListener) {
        this.file = file;
        this.hideListener = hideListener;
        String aesKey = getAesKey(password);
        this.aesService = new AesService(aesKey);
        this.init();
    }


    private void init(){
        this.title = new Label();
        this.title.setText("加载中...");
        title.setStyle("-fx-text-fill: #0035ff;-fx-font-size: 18;");

        getChildren().add(title);
        VBox.setMargin(this.title , new Insets(10 , 0 , 20 , 15));

//        WebView webView = WebViewInstance.getWebView();
        WebView webView = new WebView();
        webView.prefWidthProperty().bind(this.widthProperty());
        webView.prefHeightProperty().bind(this.heightProperty().subtract(40));
        this.engine = webView.getEngine();
        this.engine.setJavaScriptEnabled(true);
        this.engine.setUserDataDirectory(getWebviewTempDir());
        URL url = getClass().getClassLoader().getResource("static/editor.html");
        this.engine.load(url.toExternalForm());
        this.engine.reload();


        // 监听浏览器加载完成的事件
        this.engine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue == Worker.State.SUCCEEDED) {
                onLoaded();
            }
        });


        getChildren().add(webView);
    }

    public void setHideListener(Consumer<Void> hideListener) {
        this.hideListener = hideListener;
    }

    private void onLoaded(){
        JSObject window = (JSObject) engine.executeScript("window");
        this.javaBridge = new JavaBridge(this.file , this.aesService , this.hideListener);
        window.setMember("java" , this.javaBridge);

        this.title.setText(file.getName());
//        this.title.setText(getClass().getClassLoader().getResource("static/editor.html").toString());


        String originText = null;
        try {
            originText = readFile();
        } catch (Exception e) {
            System.err.println(e);
            this.passwordError = true;
            Alert alert = new Alert(Alert.AlertType.ERROR);
            alert.setTitle("提示");
            alert.setContentText("密码错误:" + e.getMessage());
            alert.showAndWait();

            this.getChildren().clear();
            return;
        }

        String finalOriginText = originText;
        setContent(finalOriginText);
    }


    public void setContent(String content){
        JSObject window = (JSObject) this.engine.executeScript("window");
        window.call("setMarkdown" , content);
    }


    private String readFile() {
        byte[] bytes = null;
        try {
            bytes = Files.readAllBytes(file.toPath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        String encryptText = new String(bytes, StandardCharsets.UTF_8);
        if(encryptText == null || encryptText.isBlank()){
            // 空文件，不需要处理
            return "";
        }else{
            // 加密文件
            String originText = this.aesService.decrypt(encryptText);
            return originText;
        }
    }

    private File getWebviewTempDir(){
        String home = System.getProperty("user.home");
        Path path = Paths.get(home, "temp", "webview");
        File f = path.toFile();
        if(!f.exists()){
            f.mkdirs();
        }
        return f;
    }

    private String getAesKey(String password) {
        String hex = SHA256.sha256Hex(password);
        String key = "";
        key += hex.substring(0, 2);
        key += hex.substring(10, 12);
        key += hex.substring(16, 18);
        key += hex.substring(20, 22);
        key += hex.substring(25, 27);
        key += hex.substring(32, 35);
        key += hex.substring(51, 53);
        key += hex.substring(56, 57);
        return key;
    }


    public static class JavaBridge{
        private File file;
        private AesService aesService;
        private Consumer<Void> hideListener;


        public JavaBridge(File file , AesService aesService , Consumer<Void> hideListener) {
            this.file = file;
            this.aesService = aesService;
            this.hideListener = hideListener;
        }

        public void setContent(String content){
            String encrypt = aesService.encrypt(content);

            try {
                Files.writeString(file.toPath() , encrypt);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * 为了安全起见，隐藏掉窗口
         */
        public void doHide(){
            if(hideListener != null){
                hideListener.accept(null);
            }
        }
    }

    public String getTitleName(){
        return title.getText();
    }

    public boolean isPasswordError() {
        return passwordError;
    }

}
